import socket
import threading
import tkinter as tk
from tkinter import filedialog, scrolledtext, messagebox
from tkinter import ttk  # 用于进度条
import struct
import time

MB = 1024 * 1024  # 定义1MB的字节数


class FileReceiver:
    def __init__(self, master):
        self.master = master
        self.master.title("文件接收端")

        # 日志显示区域
        self.log = scrolledtext.ScrolledText(master, width=60, height=10)
        self.log.pack(padx=10, pady=10)

        # 启动接收服务器按钮
        self.start_button = tk.Button(master, text="启动接收服务器", command=self.start_server)
        self.start_button.pack(pady=5)

        # 进度条
        self.progress = ttk.Progressbar(master, orient="horizontal", length=300, mode="determinate")
        self.progress.pack(pady=5)

        # 速度显示（以 MB/s 显示）
        self.speed_label = tk.Label(master, text="速度: 0.00 MB/s")
        self.speed_label.pack(pady=5)

        self.server_socket = None
        self.port = 5001  # 默认端口5001
        self.running = False

    def start_server(self):
        if self.running:
            messagebox.showinfo("提示", "服务器已经启动")
            return
        self.running = True
        self.log_message("启动服务器...")
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            self.server_socket.bind(("", self.port))
        except Exception as e:
            self.log_message("绑定端口失败: {}".format(str(e)))
            return
        self.server_socket.listen(5)
        self.log_message("服务器正在监听端口 {} ...".format(self.port))
        threading.Thread(target=self.accept_connections, daemon=True).start()

    def accept_connections(self):
        while self.running:
            try:
                client_socket, addr = self.server_socket.accept()
                self.log_message("收到连接：{}:{}".format(addr[0], addr[1]))
                threading.Thread(target=self.handle_client, args=(client_socket,), daemon=True).start()
            except Exception as e:
                self.log_message("错误: {}".format(str(e)))
                break

    def handle_client(self, client_socket):
        try:
            # 接收文件名长度（4字节，无符号整数）
            raw_fname_len = self.recvall(client_socket, 4)
            if not raw_fname_len:
                self.log_message("未收到文件名长度")
                return
            fname_len = struct.unpack("!I", raw_fname_len)[0]

            # 接收文件名
            fname_bytes = self.recvall(client_socket, fname_len)
            file_name = fname_bytes.decode("utf-8")
            self.log_message("接收到文件名: {}".format(file_name))

            # 接收文件大小（8字节，无符号长整数）
            raw_file_size = self.recvall(client_socket, 8)
            file_size = struct.unpack("!Q", raw_file_size)[0]
            self.log_message("文件大小: {} 字节".format(file_size))

            # 弹出对话框选择保存路径
            save_path = filedialog.asksaveasfilename(initialfile=file_name, title="选择保存位置")
            if not save_path:
                self.log_message("用户取消保存文件")
                client_socket.close()
                return

            # 设置进度条最大值，在主线程更新
            self.master.after(0, lambda: self.progress.config(maximum=file_size, value=0))

            received = 0
            start_time = time.time()
            update_interval = 0.5  # 每0.5秒更新一次UI
            last_update_time = time.time()
            with open(save_path, "wb") as f:
                while received < file_size:
                    chunk_size = 4096 if file_size - received >= 4096 else file_size - received
                    chunk = client_socket.recv(chunk_size)
                    if not chunk:
                        break
                    f.write(chunk)
                    received += len(chunk)

                    current_time = time.time()
                    if current_time - last_update_time >= update_interval:
                        elapsed = current_time - start_time
                        speed = received / elapsed if elapsed > 0 else received
                        self.master.after(0, lambda r=received: self.progress.config(value=r))
                        self.master.after(
                            0,
                            lambda sp=speed: self.speed_label.config(text="速度: {:.2f} MB/s".format(sp / MB))
                        )
                        last_update_time = current_time

            # 最后一次更新UI
            elapsed = time.time() - start_time
            speed = received / elapsed if elapsed > 0 else received
            self.master.after(0, lambda r=received: self.progress.config(value=r))
            self.master.after(
                0,
                lambda sp=speed: self.speed_label.config(text="速度: {:.2f} MB/s".format(sp / MB))
            )
            self.log_message("文件已保存到: {}".format(save_path))
        except Exception as e:
            self.log_message("处理客户端时发生错误: {}".format(str(e)))
        finally:
            client_socket.close()

    def recvall(self, sock, n):
        """确保接收 n 字节数据"""
        data = b""
        while len(data) < n:
            packet = sock.recv(n - len(data))
            if not packet:
                return None
            data += packet
        return data

    def log_message(self, msg):
        self.log.insert(tk.END, msg + "\n")
        self.log.see(tk.END)


if __name__ == "__main__":
    root = tk.Tk()
    app = FileReceiver(root)
    root.mainloop()
